//
// Created by 原帅 on 2022/10/9.
//

#include "Ree.h"
#include "sys/event.h"
#include "RLog.h"
#include "errno.h"

#define REE_EVENT_MAX_SIZE 16

Ree& Ree::Inst() {
    static Ree ree;
    return ree;
}

Ree::Ree() {
    reefd = kqueue();
    if (reefd == -1) {
        RLogErr("reefd=%d,error is %s", reefd, strerror(errno))
    }
}

int Ree::addResponder(int fd, ReeProcType type, ReeProcIF *procIf) {

    struct kevent kevent1 = {0};

    switch (type) {
        case READ_FD:
            EV_SET(&kevent1,fd,EVFILT_READ,EV_ADD|EV_ENABLE,0,0,NULL);
            break;
        case WRITE_FD:
            EV_SET(&kevent1,fd,EVFILT_WRITE,EV_ADD|EV_ENABLE,0,0,NULL);
            break;
        case TIMER_FD:
            EV_SET(&kevent1,fd,EVFILT_TIMER,EV_ADD|EV_ENABLE,NOTE_NSECONDS,0,NULL);
            break;
        default:
            RLogErr("unknow type:%d",type)
            return -1;
    }
    kevent(reefd, &kevent1, 1, NULL, 0, NULL);

    if (mapReeProcs.count(fd)){
        std::map<ReeProcType,ReeProcIF*> &mapTypeProc = mapReeProcs.at(fd);
        if (mapTypeProc.count(type)) {
            return 0;
        }else {
            mapTypeProc.insert(std::pair<ReeProcType,ReeProcIF*>(type,procIf));
        }
    } else {
        std::map<ReeProcType,ReeProcIF*> mapTypeProc;
        mapTypeProc.insert(std::pair<ReeProcType,ReeProcIF*>(type,procIf));
        mapReeProcs.insert(std::pair<int,std::map<ReeProcType,ReeProcIF*>>(fd,mapTypeProc));
    }
    return 0;
}

int Ree::processEvent() {
    struct timespec timespec = {0};
    timespec.tv_sec = this->timeoutSec;
    timespec.tv_nsec = this->timeoutNSec; //100毫秒
    struct kevent kevent1[REE_EVENT_MAX_SIZE] = {0};
    int ret = kevent(reefd, NULL, 0, kevent1, REE_EVENT_MAX_SIZE, &timespec);
    for (int i = 0; i < ret && i < REE_EVENT_MAX_SIZE; ++i) {
        int fd = kevent1->ident;
        if (mapReeProcs.count(fd)==0) {
            continue;
        }
        std::map<ReeProcType,ReeProcIF*> &mapProc = mapReeProcs.at(fd);
        if ((&mapProc) == NULL) continue;
        else
        {
            if (kevent1->flags & EV_ERROR) {
                // todo fd 出错， 关闭处理， map中删除，事件注册中删除
                for (int j = FD_START+1; j < FD_END; ++j) {
                    if (mapProc.count((ReeProcType)j))
                    {
                        mapProc.at((ReeProcType)j)->eventFail(fd,FD_ERROR,kevent1->data);
                    }
                }
            } else {
                if (kevent1->filter & EVFILT_READ) {
                    if (mapProc.count(READ_FD)) {
                        if (mapProc.at(READ_FD) != nullptr)
                        {
                            mapProc.at(READ_FD)->eventProcess(fd,READ_FD,kevent1->data);
                        }
                    }
                }

                if (kevent1->filter & EVFILT_WRITE) {
                    if (mapProc.count(WRITE_FD)) {
                        if (mapProc.at(WRITE_FD) != nullptr)
                        {
                            mapProc.at(WRITE_FD)->eventProcess(fd,WRITE_FD,kevent1->data);
                        }
                    }
                }

                if (kevent1->filter & EVFILT_TIMER) {
                    if (mapProc.count(TIMER_FD)) {
                        if (mapProc.at(TIMER_FD) != nullptr)
                        {
                            mapProc.at(TIMER_FD)->eventProcess(fd,TIMER_FD,kevent1->data);
                        }
                    }
                }
            }
        }
    }

    return 0;
}

int Ree::setTimeoutMSec(long msec) {
    if (msec == 0)
    {
        this->timeoutNSec = 0;
        this->timeoutSec = 0;
    }
    else
    {
        if (msec>=1000)
        {
            this->timeoutSec = msec / 1000;
            this->timeoutNSec = msec % 1000 * 1000;
        }
        else
        {
            this->timeoutSec = 0;
            this->timeoutNSec = msec;
        }
    }
    return 0;
}
